import { ExternalLink } from 'lucide-react'; import type { Metadata } from 'next'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { CompareTrayBar } from '@/components/compare/compare-tray-bar'; import { ModelsTable } from '@/components/entity/blocks'; import { Tri } from '@/components/models/badges'; import { LICENCE_DIMENSIONS, OpennessBlock } from '@/components/models/openness-block'; import { EntityBadge } from '@/components/ui/badges'; import { Hint } from '@/components/ui/hint'; import { Pagination } from '@/components/ui/pagination'; import { Container, Note } from '@/components/ui/section'; import { ApiError, apiD1, safe } from '@/lib/api'; import { fmtInt } from '@/lib/format'; import { SITE_NAME, SITE_URL } from '@/lib/site'; import type { LicenseDetail, ModelOpenness } from '@/lib/types'; type Params = { params: Promise<{ key: string }>; searchParams: Promise<{ offset?: string }> }; const LIMIT = 50; export const revalidate = 3600; async function load(key: string, offset: number): Promise { try { return await apiD1.license(key, LIMIT, offset); } catch (e) { if (e instanceof ApiError && e.notFound) notFound(); throw e; } } const tri = (v: boolean | null) => (v === true ? 'yes' : v === false ? 'no' : 'unknown'); export async function generateMetadata({ params }: Params): Promise { const { key } = await params; const l = await safe(apiD1.license(key, 1)); if (!l) return { title: 'Licence', robots: { index: false } }; const title = `${l.label} — Model licence terms & models using it`; const description = `${l.label} (${l.category}${l.spdx ? `, SPDX ${l.spdx}` : ''}): commercial use ${tri(l.commercial_use)}, redistribution ${tri(l.redistribution)}, derivatives ${tri(l.derivatives)}, hosting restrictions ${tri(l.hosting_restrictions)}, acceptable-use policy ${tri(l.acceptable_use)}. ${fmtInt(l.models.total)} canonical models use it. ${SITE_NAME}.`.slice(0, 300); const canonical = `/licenses/${encodeURIComponent(l.key)}`; return { title, description, alternates: { canonical }, openGraph: { title: `${title} | ${SITE_NAME}`, description, url: `${SITE_URL}${canonical}`, type: 'article' } }; } /** Openness view derived from the licence permissions alone (weights downloadable · commercial · redistribution · derivatives). */ function opennessFromLicence(l: LicenseDetail): ModelOpenness { const category = !l.weights_downloadable ? 'proprietary' : l.commercial_use === false || l.hosting_restrictions === true || l.derivatives === false || l.category === 'community' || l.category === 'research-only' || l.category === 'responsible-ai' ? 'restricted-weights' : 'open-weights'; const labels: Record = { proprietary: 'Closed / proprietary', 'restricted-weights': 'Restricted weights', 'open-weights': 'Open weights' }; const defs: Record = { proprietary: 'Weights are not redistributable under this licence.', 'restricted-weights': 'Weights downloadable, but the licence restricts commercial use, hosting, derivatives or field of use.', 'open-weights': 'Weights downloadable under a permissive licence allowing commercial use; code or data may be missing.', }; return { category, raw: l.key, label: labels[category] ?? category, definition: defs[category] ?? '', dimensions: { weights_available: l.weights_downloadable, source_code_available: null, training_code_available: null, training_data_disclosed: null, dataset_available: null, commercial_use_allowed: l.commercial_use, redistribution_allowed: l.redistribution, derivatives_allowed: l.derivatives }, note: 'Derived from the licence text alone — a model under this licence may still publish code or data (see its page).', }; } export default async function LicensePage({ params, searchParams }: Params) { const { key } = await params; const { offset: off } = await searchParams; const offset = Math.max(0, Number(off) || 0); const l = await load(key, offset); const canonical = `/licenses/${encodeURIComponent(l.key)}`; const ld = { '@context': 'https://schema.org', '@type': 'CreativeWork', name: l.label, url: `${SITE_URL}${canonical}`, alternateName: l.aliases, sameAs: l.url ?? undefined, identifier: l.spdx ?? l.key, description: `${l.category} licence · commercial use ${tri(l.commercial_use)} · redistribution ${tri(l.redistribution)} · derivatives ${tri(l.derivatives)}` }; return (